package com.study.cms.auth.service.impl;


import com.study.cms.auth.annotation.RonghuanetPermission;
import com.study.cms.auth.domain.Permission;
import com.study.cms.auth.mapper.PermissionMapper;
import com.study.cms.auth.service.PermissionScanService;
import com.study.cms.basic.utils.ClassUtils;
import com.study.cms.basic.utils.RequestTypeEnum;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.List;
import java.util.Objects;

@Service
public class PermissionScanServiceImpl implements PermissionScanService {

    @Value("${permission.scan-base-package}")
    private String scanBasePackage;

    @Autowired
    private PermissionMapper permissionMapper;

    @Transactional
    @Override
    public void scan() {
//        项目启动监听器初始化到scan方法
//        1.首先可以通过 Class 对象的 isAnnotationPresent() 方法判断它是否应用了某个注解
//               这个从配置文件中拿到需要扫描的controller 包名 通过classutils工具类处理成类名
        permissionMapper.removeAll();
        System.out.println(scanBasePackage);
        List<Class> allClassName = ClassUtils.getAllClassName(scanBasePackage);
        System.out.println(allClassName);
        if (allClassName.size() > 0 && allClassName != null) {
            for (Class c : allClassName) {
                //拿到class 对象
                boolean annotationPresent = c.isAnnotationPresent(RonghuanetPermission.class);
                if (!annotationPresent) {
                    continue;
                }
                //不强转 拿不到value
                RonghuanetPermission ronghuanetPermission = (RonghuanetPermission) c.getAnnotation(RonghuanetPermission.class);
                String Headname = ronghuanetPermission.name();
                String Headdesc = ronghuanetPermission.desc();
                System.out.println("----类上的name");
                System.out.println(Headname);

                //还要拿headURL
                RequestMapping requestMapping = (RequestMapping) c.getAnnotation(RequestMapping.class);
                String headURL = requestMapping.value()[0];
                System.out.println("+++++++++++++类上URL+++++++++++++");
                System.out.println(headURL);

                //类上的 权限 拿了就加 比如 部门 员工
                Permission permission = new Permission();
                permission.setName(Headname);
                permission.setDescs(Headdesc);
                permission.setUrl(headURL);
                permission.setSn(c.getSimpleName());

                permissionMapper.insert(permission);

                //拿到该类下所有方法 进行遍历判断
                Method[] methods = c.getMethods();
                for (Method m : methods) {
                    //重复判断类上注解操作
                    RonghuanetPermission mpermission = m.getAnnotation(RonghuanetPermission.class);
                    if (Objects.isNull(mpermission)) {
                        continue;
                    }
                    String mname = mpermission.name();
                    //方法上的name
                    System.out.println("------方法上name--------");
                    System.out.println(mname);
                    //方法上的URL  使用枚举 因为不知道是 xxxMapping
                    String methodUrl = getMethodUrl(m);
                    System.out.println("------方法上的url------");
                    System.out.println(methodUrl);
                    String sn = c.getSimpleName()+":"+m.getName();

                    Permission method = new Permission();
                    method.setName(mname);
                    method.setDescs(mpermission.desc());
                    method.setSn(sn);

                    //处理方法上的URL headurl+methodURL
                    method.setUrl(headURL+methodUrl);
                    method.setParent(permission);

                    permissionMapper.insert(method);



                }


            }

        }
//          1.2 遍历类 拿到方法


//        2.然后通过 getAnnotation() 方法来获取 Annotation 对象。

    }

    private String getMethodUrl(Method method) {
        String methodUrl = "";
        // 取枚举中定义的所有的请求类型
        RequestTypeEnum[] requestTypeEnums = RequestTypeEnum.values();
        for (RequestTypeEnum typeEnum : requestTypeEnums) {
            // 根据枚举中的不同的请求类型的class获取该类型对应的注解对象
            Annotation annotation = method.getAnnotation(typeEnum.getRequestType());
            // 如果该请求类型注解不存在就跳过
            if (Objects.isNull(annotation)) {
                continue;
            }
            try {
                // 如果该请求类型注解存在,就获取它里面的value方法
                Method annotationMethod = annotation.annotationType().getMethod("value");
                // 通过invoke调用该对象的value方法,获取结果
                String[] value = (String[]) annotationMethod.invoke(annotation);
                // 如果value不为空且长度大于0,就赋值给methodUrl,并跳出循环
                if (value != null && value.length > 0) {
                    methodUrl = value[0];
                    break;
                }
            } catch (Exception e) {
                e.printStackTrace();
                continue;
            }
        }
        return methodUrl;
    }
}


// 扫描所有controller包下面打了@RonghuaPermission的类和方法
// 1 获取特定包下面所有类的Class字节码文件 controller这个包下面的类
//        System.out.println(this.scanBasePackage);
//                List<Class> clazzs = ClassUtils.getAllClassName(this.scanBasePackage);
//        List<Permission> permissions = new ArrayList<>();
//
//        if(clazzs != null && clazzs.size() > 0){
//        // 2 循环拿到的所有的controller的字节码文件
//        for (Class clazz : clazzs) {
//        // 2.1 判断类上是否有@RonghuaPermission注解,如果没有就直接跳过
//        RonghuanetPermission clazzAnnotation = (RonghuanetPermission)clazz.getAnnotation(RonghuanetPermission.class);
//        if(Objects.isNull(clazzAnnotation)){
//        continue;
//        }
//        // 获取类上面的url路径
//        RequestMapping requestMapping = (RequestMapping)clazz.getAnnotation(RequestMapping.class);
//        String clazzUrl = requestMapping.value()[0];
//
//        // 将类上面的@RonghuaPermisson注解解析为一个Permission对象
//        Permission parent = new Permission();
//        parent.setName(clazzAnnotation.name());
//        parent.setDescs(clazzAnnotation.desc());
//        parent.setUrl(clazzUrl);
//        parent.setSn(clazz.getSimpleName());
//        permissions.add(parent);
//
//        // 2.2 如果类上有注解,获取类里面所有的方法
//        Method[] methods = clazz.getMethods();
//        // 3 遍历所有的方法,判断方法上是否有@RonghuaPermission
//        for (Method method : methods) {
//        // 3.1 如果没有这个注解,就说明当前方法不需要权限就可以直接访问了,所以就跳过不处理
//        RonghuanetPermission ronghuaPermission = method.getAnnotation(RonghuanetPermission.class);
//        if(Objects.isNull(ronghuaPermission)){
//        continue;
//        }
//        // 3.2 如果有的话,就要获取name desc 要拼接sn url 将它们封装成一个Permission对象
//        Permission permission = new Permission();
//        permission.setName(ronghuaPermission.name());
//        permission.setDescs(ronghuaPermission.desc());
//        // 处理sn  类名:方法名
//        String sn = clazz.getSimpleName()+":"+method.getName();
//        permission.setSn(sn);
//        // 处理url  url指的是前端在访问时需要访问的url,所以它是类上面的@RequestMapping的值+方法上面的那个url
//        String methodUrl = getMethodUrl(method);
//        permission.setUrl(clazzUrl+methodUrl);
//        permission.setParent(parent);   // 以类上面解析的permission对象作为父权限对象
//        permissions.add(permission);
//        }
//        }
//        }
//        // 4 将Permission对象存到数据库
//        // 问题:每次启动项目,都要来扫描一次,并添加到数据库,这样子的话是不合理的
//        // 解决方案:方案一: 在新增时 根据sn判断一下这个权限在数据库是否存在,如果已经存在就不添加了 如果不存在再添加
//        //               问题: 这个权限如果之前是有的,但是现在方法上面的注解删掉了,这样的话 就不好处理这种情况
//        //               要先查询出数据库里面所有的权限,然后再和刚刚封装好的权限对象做比较,如果数据库有,而封装后的没有,就要将数据库的那个权限删除掉
//        // 方案二: 直接先删除所有权限,再全部 全量新增
//        permissionMapper.removeAll();
//        for (Permission permission : permissions) {
//        permissionMapper.insert(permission);
//        }
//        }
//
///**
// * 获取方法上面的url
// * @param method
// * @return
// */
//private String getMethodUrl(Method method){
//        String methodUrl = "";
//        // 取枚举中定义的所有的请求类型
//        RequestTypeEnum[] requestTypeEnums = RequestTypeEnum.values();
//        for (RequestTypeEnum typeEnum : requestTypeEnums) {
//        // 根据枚举中的不同的请求类型的class获取该类型对应的注解对象
//        Annotation annotation = method.getAnnotation(typeEnum.getRequestType());
//        // 如果该请求类型注解不存在就跳过
//        if(Objects.isNull(annotation)){
//        continue;
//        }
//        try {
//        // 如果该请求类型注解存在,就获取它里面的value方法
//        Method annotationMethod = annotation.annotationType().getMethod("value");
//        // 通过invoke调用该对象的value方法,获取结果
//        String[] value = (String[]) annotationMethod.invoke(annotation);
//        // 如果value不为空且长度大于0,就赋值给methodUrl,并跳出循环
//        if(value != null && value.length > 0){
//        methodUrl = value[0];
//        break;
//        }
//        }catch (Exception e) {
//        e.printStackTrace();
//        continue;
//        }
//        }
//        return methodUrl;
//        /*PutMapping putMapping = method.getAnnotation(PutMapping.class);
//        if(Objects.nonNull(putMapping)){
//            methodUrl = putMapping.value() != null && putMapping.value().length > 0 ? putMapping.value()[0] : "";
//        }
//        PostMapping postMapping = method.getAnnotation(PostMapping.class);
//        if(Objects.nonNull(postMapping)){
//            methodUrl = postMapping.value() != null && postMapping.value().length > 0 ? postMapping.value()[0] : "";
//        }
//        GetMapping getMapping = method.getAnnotation(GetMapping.class);
//        if(Objects.nonNull(getMapping)){
//            methodUrl = getMapping.value() != null && getMapping.value().length > 0? getMapping.value()[0] : "";
//        }
//        DeleteMapping deleteMapping = method.getAnnotation(DeleteMapping.class);
//        if(Objects.nonNull(deleteMapping)){
//            methodUrl = deleteMapping.value() != null && deleteMapping.value().length > 0 ? deleteMapping.value()[0] : "";
//        }
//        PatchMapping patchMapping = method.getAnnotation(PatchMapping.class);
//        if(Objects.nonNull(patchMapping)){
//            methodUrl = patchMapping.value() != null && patchMapping.value().length > 0 ? patchMapping.value()[0] : "";
//        }*/
//        //return methodUrl;
//        }
